
package com.jf.cloud.live.service.impl;

import cn.binarywang.wx.miniapp.bean.live.WxMaLiveResult;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.jf.cloud.api.platform.config.FeignShopConfig;
import com.jf.cloud.api.product.feign.SpuFeignClient;
import com.jf.cloud.common.constant.Constant;
import com.jf.cloud.common.database.dto.PageDTO;
import com.jf.cloud.common.database.util.PageUtil;
import com.jf.cloud.common.database.vo.PageVO;
import com.jf.cloud.common.exception.LuckException;
import com.jf.cloud.common.product.vo.SpuVO;
import com.jf.cloud.common.response.ServerResponseEntity;
import com.jf.cloud.common.util.Arith;
import com.jf.cloud.live.config.WxConfig;
import com.jf.cloud.live.constant.LiveInterfaceType;
import com.jf.cloud.live.constant.LiveProdStatusType;
import com.jf.cloud.live.constant.WxErrorCode;
import com.jf.cloud.live.dto.LiveProdStoreDTO;
import com.jf.cloud.live.mapper.LiveProdLogMapper;
import com.jf.cloud.live.mapper.LiveProdStoreMapper;
import com.jf.cloud.live.model.LiveProdLog;
import com.jf.cloud.live.model.LiveProdStore;
import com.jf.cloud.live.request.GoodsInfoReqParam;
import com.jf.cloud.live.request.UpdateGoodsInfoReqParam;
import com.jf.cloud.live.response.GoodsInfoRespParam;
import com.jf.cloud.live.response.WxLiveProdResponse;
import com.jf.cloud.live.service.LiveLogService;
import com.jf.cloud.live.service.LiveProdStoreService;
import com.jf.cloud.live.service.LiveRoomProdService;
import com.jf.cloud.live.util.WxImageUtil;
import com.jf.cloud.live.util.WxInterfaceUtil;
import ma.glasnost.orika.MapperFacade;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.collections.CollectionUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static javax.swing.plaf.synth.ColorType.MAX_COUNT;

/**
 * 直播商品
 *
 * @author zz
 * @date 2022-08-17 17:09:06
 */
@Service
public class LiveProdStoreServiceImpl implements LiveProdStoreService {

    @Autowired
    private LiveProdStoreMapper liveProdStoreMapper;
    @Autowired
    private  RedissonClient redissonClient;
    @Autowired
    private LiveLogService liveLogService;
    @Autowired
    private WxImageUtil wxImageUtil;
    private static final String REDISSON_LOCK_PREFIX = "redisson_lock:";
    private static final Logger log = LoggerFactory.getLogger(LiveProdStoreServiceImpl.class);
    @Autowired
    private WxConfig wxConfig;
    @Autowired
    private WxInterfaceUtil wxUtil;
    @Autowired
    private LiveProdLogMapper liveProdLogMapper;
    @Autowired
    private LiveRoomProdService liveRoomProdService;
    @Autowired
    private FeignShopConfig shopConfig;
    @Autowired
    private MapperFacade mapperFacade;
    private WxInterfaceUtil wxInterfaceUtil;
    @Autowired
    private SpuFeignClient spuFeignClient;

    @Override
    public PageVO<LiveProdStore> page(PageDTO pageDTO, LiveProdStoreDTO liveProdStoreDTO) {
        PageVO<LiveProdStore> liveProdStorePage = PageUtil.doPage(pageDTO, () -> liveProdStoreMapper.list(liveProdStoreDTO));
        //获取商品图片信息
        return getSpuInfo(liveProdStorePage);
    }

    @Override
    public LiveProdStore getByLiveProdStoreId(Long liveProdStoreId) {
        return liveProdStoreMapper.getByLiveProdStoreId(liveProdStoreId);
    }

    @Override
    public void save(LiveProdStore liveProdStore) {
        liveProdStoreMapper.save(liveProdStore);
    }

    @Override
    public void update(LiveProdStore liveProdStore) {
        liveProdStoreMapper.update(liveProdStore);
    }

    @Override
    public void deleteById(Long liveProdStoreId) {
        liveProdStoreMapper.deleteById(liveProdStoreId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean submitVerify(LiveProdStore liveProdStore) {
        RLock rLock = redissonClient.getLock(REDISSON_LOCK_PREFIX + "liveProdSubmitVerify" + liveProdStore.getShopId());
        try {
            if (rLock.tryLock(Constant.FIVE, Constant.SIXTY, TimeUnit.SECONDS)) {
                // 1.校验今日可用次数并保存or修改商家次数记录
                liveLogService.checkNumsAndSaveLog(liveProdStore.getShopId(), LiveInterfaceType.ADD_PROD_AUDIT, "提交审核");
                LiveProdStore update = new LiveProdStore();
                update.setLiveProdStoreId(liveProdStore.getLiveProdStoreId());
                Date date = new Date();
                update.setUpdateTime(date);
                update.setVerifyTime(date);
                update.setStatus(LiveProdStatusType.NO_EXAMINE.value());
                // 发起微信审核, 先获取微信的media_id
                GoodsInfoRespParam goodsInfo = getInfoRespParam(liveProdStore, update);
                boolean prodStoreOk;
                boolean prodLogOk;
                // 获取到的goodsId存起来
                prodStoreOk = liveProdStoreMapper.update(update) > 0;
                // 添加日志
                prodLogOk = isLogOk(liveProdStore, date, goodsInfo);
                return prodStoreOk && prodLogOk;
            } else {
                // 网络异常
                throw new LuckException("网络异常");
            }
        } catch (WxErrorException e) {
            log.info("获取access_token异常");
        } catch (InterruptedException e) {
            log.error("InterruptedException:", e);
        } finally {
            try {
                if (rLock.isLocked()) {
                    rLock.unlock();
                }
            } catch (Exception e){
                log.error("Exception:", e);
            }
        }
        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeWxLiveProdById(Long liveProdStoreId, Long shopId) {
        LiveProdStore liveProdStore = liveProdStoreMapper.getByLiveProdStoreId(liveProdStoreId);
        // 状态为审核通过的商品进行移除微信商品库的数据、扣除次数
        if(Objects.equals(liveProdStore.getStatus(),LiveProdStatusType.EXAMINE_SUCCESS.value())){
            // 1.校验今日可用次数并保存or修改商家次数记录
            liveLogService.checkNumsAndSaveLog(shopId, LiveInterfaceType.DELETE_PROD, "删除商品库商品");
            try {
                wxConfig.getWxMaService().getLiveGoodsService().deleteGoods(liveProdStore.getGoodsId());
            } catch (WxErrorException e) {
                //商品在微信直播控制台已被删除 (微信返回错误码：300015：goodsId is not exist),则不抛出异常，直接在数据库删除
                Integer errorCode = 300015;
                if (!Objects.equals(e.getError().getErrorCode(), WxErrorCode.GOODSID_IS_NOT_EXIST.value())) {
                    // 删除直播商品失败
                    log.error("删除微信直播商品失败！",liveProdStore.getGoodsId());
                    log.error(e.getMessage());
                    throw new LuckException("删除直播商品失败");
                }
            }
        }
        // 移除数据库的数据包括关联
        liveProdStore.setStatus(-1);
        liveProdStoreMapper.update(liveProdStore);
        liveRoomProdService.deleteById(liveProdStoreId);
    }

    private boolean isLogOk(LiveProdStore liveProdStore, Date date, GoodsInfoRespParam goodsInfo) {
        boolean prodLogOk;
        LiveProdLog prodLog = new LiveProdLog();
        prodLog.setLiveProdStoreId(liveProdStore.getLiveProdStoreId());
        prodLog.setUpdateTime(date);
        prodLog.setStatus(1);
        prodLog.setGoodsId(goodsInfo.getGoodsId());
        prodLog.setAuditId(goodsInfo.getAuditId());
        prodLogOk = liveProdLogMapper.save(prodLog) > 0;
        return prodLogOk;
    }

    @NotNull
    private GoodsInfoRespParam getInfoRespParam(LiveProdStore liveProdStore, LiveProdStore update) throws WxErrorException {
        String mediaId = wxImageUtil.wxImageUpload(liveProdStore.getCoverPic());
        update.setConverImgUrl(mediaId);
        GoodsInfoReqParam reqParam = new GoodsInfoReqParam();
        reqParam.setCoverImgUrl(mediaId);
        reqParam.setName(liveProdStore.getName());
        reqParam.setPriceType(liveProdStore.getPriceType());
        reqParam.setPrice(liveProdStore.getPrice());
        reqParam.setPrice2(liveProdStore.getPrice2());
        reqParam.setUrl(liveProdStore.getUrl());
//        reqParam.setUrl("package-shop/detail/detail?spuId=598420688896");
        reqParam.setAccessToken(wxConfig.getWxMaService().getAccessToken());
        GoodsInfoRespParam goodsInfo = wxUtil.prodAddVerify(reqParam);
        update.setGoodsId(goodsInfo.getGoodsId());
        update.setStatus(LiveProdStatusType.EXAMINING.value());
        return goodsInfo;
    }

    @Override
    public PageVO<LiveProdStore> pageProdByRoomId(PageDTO page, Integer roomId) {
        PageVO<LiveProdStore> liveProdStorePage = PageUtil.doPage(page, () -> liveProdStoreMapper.pageProdByRoomId(roomId));
        return getSpuInfo(liveProdStorePage);
    }

    /**
     * 获取商品图片信息
     */
    public PageVO<LiveProdStore>  getSpuInfo(PageVO<LiveProdStore> liveProdStorePage){
        List<LiveProdStore> list = liveProdStorePage.getList();
        if(CollUtil.isNotEmpty(list)){
            List<Long> prodIds = list.stream().map(LiveProdStore::getProdId).collect(Collectors.toList());
            ServerResponseEntity<List<SpuVO>> responseEntity = spuFeignClient.getDetailBySpuIds(prodIds);
            List<SpuVO> spuVOS = responseEntity.getData();
            list.forEach((item) ->item.setPic(spuVOS.stream().filter(spuVO -> Objects.equals(spuVO.getSpuId(), item.getProdId())).findFirst().get().getMainImgUrl()));
            liveProdStorePage.setList(list);
        }
        return liveProdStorePage;
    }

    @Override
    public void synchronousWxLiveProds() {
        LiveProdStoreDTO liveProdStoreDTO = new LiveProdStoreDTO();
        List<LiveProdStore> liveProdStores = liveProdStoreMapper.list(liveProdStoreDTO);
        List<Integer> ids = new ArrayList<>();
        liveProdStores.forEach(liveProdStore -> {
            if(Objects.nonNull(liveProdStore.getGoodsId())){
                ids.add(liveProdStore.getGoodsId());
            }
        });
        WxMaLiveResult wxMaLiveResult;
        List<WxMaLiveResult.Goods> goods = new ArrayList<>();
        try {
            int count = (int)Math.ceil(Arith.div(ids.size(),20));
            for (int i = 0; i < count; i++) {
                List<Integer> goodsIds = new ArrayList<>();
                int maxLength = Math.min(MAX_COUNT * (i + 1),ids.size());
                for (int j = MAX_COUNT * i ; j < maxLength; j++) {
                    goodsIds.add(ids.get(j));
                }
                wxMaLiveResult = wxConfig.getWxMaService().getLiveGoodsService().getGoodsWareHouse(goodsIds);
                goods.addAll(wxMaLiveResult.getGoods());
            }
        }catch (WxErrorException e){
            log.error("获取直播间商品状态失败！");
            log.error(e.getMessage());
            return;
        }

        Date date = new Date();
        if(CollectionUtils.isEmpty(goods)){
            return;
        }
        Map<Integer, Integer> wxGoodsMap = goods.stream().collect(Collectors.toMap(WxMaLiveResult.Goods::getGoodsId, WxMaLiveResult.Goods::getAuditStatus));
        for (LiveProdStore liveProdStore : liveProdStores) {
            if(Objects.isNull(liveProdStore.getGoodsId()) || !wxGoodsMap.containsKey(liveProdStore.getGoodsId()) || Objects.isNull(wxGoodsMap.get(liveProdStore.getGoodsId()))){
                continue;
            }
            Integer status = wxGoodsMap.get(liveProdStore.getGoodsId());
            // 从任意非审核通过的状态变成审核通过，修改审核时间
            if(!Objects.equals(liveProdStore.getStatus(),status) &&
                    Objects.equals(status,LiveProdStatusType.EXAMINE_SUCCESS.value())){
                liveProdStore.setSuccessTime(date);
            }
            liveProdStore.setStatus(status);
        }
        // 批量修改商品状态
        liveProdStoreMapper.updateBatch(liveProdStores);
    }

    @Override
    public void removeOldLiveProd() {
        // 十天前的时间
        DateTime dateTime = DateUtil.offsetDay(new Date(), -10);
        Date date = new Date();
        // 查询十天前上架的商品
        LiveProdStoreDTO liveProdStoreDTO = new LiveProdStoreDTO();
        liveProdStoreDTO.setStatus(LiveProdStatusType.EXAMINE_SUCCESS.value());
        liveProdStoreDTO.setEndTime(dateTime);
        List<LiveProdStore> prodStoreList = liveProdStoreMapper.list(liveProdStoreDTO);
        if(CollectionUtils.isEmpty(prodStoreList)){
            return;
        }
        List<Long> ids = new ArrayList<>();
        for (LiveProdStore liveProdStore : prodStoreList) {
            liveProdStore.setCancelTime(date);
            liveProdStore.setStatus(LiveProdStatusType.PLATFORM_BREAK.value());
            ids.add(liveProdStore.getLiveProdStoreId());
            try {
                // 移除微信商品库的数据
                wxConfig.getWxMaService().getLiveGoodsService().deleteGoods(liveProdStore.getGoodsId());
                boolean deleteGoods = wxConfig.getWxMaService().getLiveGoodsService().deleteGoods(liveProdStore.getGoodsId());
                if (!deleteGoods) {
                    // 删除直播商品失败
                    throw new Exception();
                }
            }catch (Exception e){
                log.error("删除直播商品失败！",liveProdStore.getGoodsId());
                log.error(e.getMessage());
            }
        }
        // 批量修改
        liveProdStoreMapper.updateBatch(prodStoreList);
        // 删除直播间和商品的关联
        liveRoomProdService.deleteBatchById(ids);
    }

    @Override
    public List<LiveProdStore> list(LiveProdStoreDTO liveProdStore) {
        return liveProdStoreMapper.list(liveProdStore);
    }

    @Override
    public PageVO<LiveProdStore> pageProdStoreByIds(PageDTO page, List<Long> filterProdStoreIds) {
        PageVO<LiveProdStore> liveProdStorePage = PageUtil.doPage(page, () -> liveProdStoreMapper.pageProdStoreByIds(filterProdStoreIds));
        return getSpuInfo(liveProdStorePage);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateWxLiveProdById(LiveProdStore liveProdStore) throws WxErrorException {
        // 两种情况修改
        // 没有提交微信商品库的修改
        if(Objects.isNull(liveProdStore.getProdId())){
            throw new LuckException("请选择商品");
        }
        if(Objects.equals(liveProdStore.getStatus(), LiveProdStatusType.NO_EXAMINE.value())){
            liveProdStoreMapper.update(liveProdStore);
        }
        if(Objects.equals(liveProdStore.getStatus(), LiveProdStatusType.EXAMINING.value())){
            // 商品正在审核中，无法进行修改
            throw new LuckException("商品正在审核中，无法进行修改");
        }
        if(Objects.equals(liveProdStore.getStatus(), LiveProdStatusType.EXAMINE_SUCCESS.value())){
            // 1.校验今日可用次数并保存or修改商家次数记录
            liveLogService.checkNumsAndSaveLog(liveProdStore.getShopId(), LiveInterfaceType.UPDATE_PROD, "修改商品库商品");

            // 提交到微信商品库的修改
            LiveProdStore prodStore = new LiveProdStore();
            prodStore.setPrice(liveProdStore.getPrice());
            prodStore.setPrice2(liveProdStore.getPrice2());
            prodStore.setGoodsId(liveProdStore.getGoodsId());
            prodStore.setUpdateTime(liveProdStore.getUpdateTime());
            prodStore.setPriceType(liveProdStore.getPriceType());
            liveProdStoreMapper.update(liveProdStore);
            // 修改微信商品库
            UpdateGoodsInfoReqParam goodsInfo = mapperFacade.map(prodStore,UpdateGoodsInfoReqParam.class);
            goodsInfo.setAccessToken(wxConfig.getWxMaService().getAccessToken());
            WxLiveProdResponse<Void> liveProdResponse = wxInterfaceUtil.prodUpdate(goodsInfo);
            if(!liveProdResponse.isSuccess()){
                // 更新直播商品库失败
                throw new LuckException("更新直播商品库失败");
            }
        }
    }
}
